// *************************************************************************
//
//                                JOST
//
//               Copyright (C) 2007 by Angelo Corsaro.
//                       <angelo.corsaro@gmail.com>
//                          All Rights Reserved.
//
//   Permission to use, copy, modify, and distribute this software and
//   its  documentation for any purpose is hereby  granted without fee,
//   provided that the above copyright notice appear in all copies and
//   that both that copyright notice and this permission notice appear
//   in  supporting  documentation. I don't make  any  representations
//   about the  suitability  of this  software for any  purpose. It is
//   provided "as is" without express or implied warranty.
//
//
// *************************************************************************
//  
// *************************************************************************

#ifndef _JOST_JSON_GRAMMAR_H_
#define _JOST_JSON_GRAMMAR_H_

//#include <boost/spirit/core.hpp>
#include <boost/spirit/include/classic_core.hpp>
//#include <boost/spirit/utility/confix.hpp>
#include <boost/spirit/include/classic_confix.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#include <stack>


/*   
     Below is reported for convenience the JSON grammar expressed in
     EBNF. The reminder of the file provides the SPIRIT version for this
     grammar.

     Object  ::= '{' '}' 
     |  '{' Members '}'

     Members ::= Pair 
     |  Pair, Members

     Pair    ::= string ':' Value

     Array   ::= '[' ']'
     |  '[' Elements ']'

     Elements ::= Value
     |  Value, Elements

     Value    ::= Array
     |  Object
     |  integer
     |  real
     |  string
     |  true
     |  false
     |  null  

     
*/

namespace jost 
{
    
enum parsing_state
{
    ROOT_OBJECT = 0,
    OBJECT = 1,
    ARRAY = 2,
    FIELD = 3
};

struct Token {
    parsing_state pstate;
    std::string   field;
    jost::Value*  value;
};


using namespace boost::spirit::classic;


//////////////////////////////////////////////////////////////////////
//   -- Object Actions --
//////////////////////////////////////////////////////////////////////
template <typename PARSER>
struct object_scope_begin_functor
{
    object_scope_begin_functor(PARSER* p) 
        : parser_(p) 
        {}
    
    void operator()(const char& ch) const {
        Token t;
        if (parser_->pstack.empty())
            t.pstate = ROOT_OBJECT;
        else
            t.pstate = OBJECT;
        t.value = new jost::Object();
        parser_->pstack.push(t);        
        
    }
    
    PARSER* parser_;
};

template <typename PARSER>
struct object_scope_end_functor 
{
    object_scope_end_functor(PARSER* p) 
        : parser_(p) 
        {}
    
    void operator()(const char& ch) const {
        Token& t = parser_->pstack.top();
        jost::Object* o = jost::extract<jost::Object>(t.value);
        jost::Object* outer;
        
        std::string field;
        jost::Array* a;
        
        switch (t.pstate) {
            case ROOT_OBJECT:
                parser_->pstack.pop();
                parser_->parsed_object_ = o;
                break;
            case OBJECT:
                parser_->pstack.pop();
                switch (parser_->pstack.top().pstate) {
                    case FIELD:
                        field = parser_->pstack.top().field;
                        parser_->pstack.pop();
                        outer = jost::extract<jost::Object>(parser_->pstack.top().value);
                        outer->set_field(field, o);
                        break;
                    case ARRAY:
                        a =
                            jost::extract<jost::Array>(parser_->pstack.top().value);
                        a->push_back(t.value);
                        break;
                    default:
                        break;
                }
            default:
                break;
                
        }
    }
    
    PARSER* parser_;
};

template <typename PARSER>
struct empty_object_scope_end_functor
{
    empty_object_scope_end_functor(PARSER* p, object_scope_end_functor<PARSER>& osef) 
        : parser_(p)
        , osef_(osef)
        {}

    void operator()(const char& ch) const {
        Token t;
        if (parser_->pstack.empty())
            t.pstate = ROOT_OBJECT;
        else
            t.pstate = OBJECT;
        t.value = new jost::Object();
        parser_->pstack.push(t);
        osef_('}');
    }

    PARSER* parser_;
    object_scope_end_functor<PARSER>& osef_;
};


//////////////////////////////////////////////////////////////////////
//   -- Array Actions --
//////////////////////////////////////////////////////////////////////
template <typename PARSER>
struct array_scope_begin_functor
{
    array_scope_begin_functor(PARSER* p) 
        : parser_(p) 
        {}

    void operator()(const char& ch) const {
        Token t;
        t.pstate = ARRAY;
        t.value = new jost::Array();
        parser_->pstack.push(t);
    }

    PARSER* parser_;
};

template <typename PARSER>
struct array_scope_end_functor 
{
    array_scope_end_functor(PARSER* p) 
        : parser_(p) 
        {}
    
    void operator()(const char& ch) const {
        Token& t = parser_->pstack.top();
        jost::Array* a = jost::extract<jost::Array>(t.value);
        jost::Array* outer;

        jost::Object* o;
        std::string field;

        parser_->pstack.pop();
        switch (parser_->pstack.top().pstate) {
            case FIELD:
                field = parser_->pstack.top().field;
                parser_->pstack.pop();
                o = jost::extract<jost::Object>(parser_->pstack.top().value);
                o->set_field(field, a);
                break;
            case ARRAY:
                outer =
                    jost::extract<jost::Array>(parser_->pstack.top().value);
                outer->push_back(a);
                break;
            default:
                break;
        }
    }
    
    PARSER* parser_;
};
    
template <typename PARSER>
struct empty_array_scope_end_functor
{
    empty_array_scope_end_functor(PARSER* p, array_scope_end_functor<PARSER>& asef) 
        : parser_(p)
        , asef_(asef)
        {}

    void operator()(const char& ch) const {
        Token t;
        t.pstate = ARRAY;
        t.value = new jost::Array();
        parser_->pstack.push(t);
        asef_(']');
    }

    PARSER* parser_;
    array_scope_end_functor<PARSER>& asef_;
};


//////////////////////////////////////////////////////////////////////
//   -- Field Actions --
//////////////////////////////////////////////////////////////////////
template <typename PARSER>
struct field_functor
{
    field_functor(PARSER* p) 
        : parser_(p) 
        {}

    template <typename IteratorT>
    void operator()(IteratorT first, IteratorT last) const {
        Token t;
        t.pstate = FIELD;
        t.field = std::string(++first, --last);
        parser_->pstack.push(t);
    }

    PARSER* parser_;

};

    
//////////////////////////////////////////////////////////////////////
// -- Bool Types Action --
//////////////////////////////////////////////////////////////////////

template <typename PARSER>
void
reduce_value(PARSER* parser_, jost::Value* value)
{
    Token t = parser_->pstack.top();
    std::string str;
    
    jost::Object* o;
    jost::Array* a;
    
    switch(t.pstate) {
        case FIELD:
            str = t.field;
            parser_->pstack.pop();
            o = jost::extract<jost::Object>(parser_->pstack.top().value);
                o->set_field(t.field, value);
                break;
                
        case ARRAY:
            a = jost::extract<jost::Array>(t.value);
            a->push_back(value);
            break;
            
        default:
                break;
    }

}


template <bool B, typename PARSER>
struct bool_functor 
{
    bool_functor(PARSER* p)
        : parser_(p) 
        {}

    template <typename IteratorT>
    void operator()(IteratorT first, IteratorT last) const {
        jost::Boolean* b = new jost::Boolean(B);
        reduce_value(parser_, b);
    }
    PARSER* parser_;    
};

template <typename PARSER>
struct nil_functor 
{
    nil_functor(PARSER* p)
        : parser_(p) 
        {}
    
    template <typename IteratorT>
    void operator()(IteratorT first, IteratorT last) const {
        jost::Nil* n = new jost::Nil(0);
        reduce_value(parser_, n);
    }

    
    PARSER* parser_;    
};
    
//////////////////////////////////////////////////////////////////////
// -- Integral Types Action --
//////////////////////////////////////////////////////////////////////


template <typename JSON_TYPE, typename T, typename PARSER>
struct integral_functor
{
    integral_functor(PARSER* p)
        : parser_(p) 
        {}

    template <typename IteratorT>
    void
    operator()(IteratorT first, IteratorT last) const {
        std::string str(++first, --last);
        JSON_TYPE* jt = new JSON_TYPE(str);
        Token t = parser_->pstack.top();
        
        jost::Object* o;
        jost::Array* a;
        
        switch(t.pstate) {
            case FIELD:
                str = t.field;
                parser_->pstack.pop();
                o = jost::extract<jost::Object>(parser_->pstack.top().value);
                o->set_field(t.field, jt);
                break;
                
            case ARRAY:
                a = jost::extract<jost::Array>(t.value);
                a->push_back(jt);
                break;
                
            default:
                break;
        }
    }
    
    
    void operator()(const T& val) const {
        JSON_TYPE* jt = new JSON_TYPE(val);
        Token t = parser_->pstack.top();

        jost::Object* o;
        jost::Array* a;
        std::string str;
        
        switch (t.pstate) {
            case FIELD:
                str = t.field;
                parser_->pstack.pop();
                o = jost::extract<jost::Object>(parser_->pstack.top().value);
                o->set_field(t.field, jt);
                break;
                
            case ARRAY:
                a = jost::extract<jost::Array>(t.value);
                a->push_back(jt);
                break;
                
            default:
                break;
        }
    }
    

    PARSER* parser_;
};


class json_parser : public boost::spirit::classic::grammar<json_parser>
{
public:
    typedef std::stack<Token> parse_stack;
    
public:

    /**
     * JSON Parser constructor.
     */
    json_parser()
        : int_f(this)
        , real_f(this)
        , string_f(this)
        , true_f(this)
        , false_f(this)
        , nil_f(this)
        , object_scope_end_f(this)
        , object_scope_begin_f(this)
        , array_scope_end_f(this)
        , array_scope_begin_f(this)
        , empty_object_scope_end_f(this, object_scope_end_f)
        , empty_array_scope_end_f(this, array_scope_end_f)
        , field_f(this)
        , parsed_object_(0)
        { }
    
    template <typename ScannerT>
    struct definition
    {
	definition(json_parser const& self) {
            
            json_parser* parser = const_cast<json_parser*>(&self);

            object = ch_p('{') >>  ch_p('}')[parser->empty_object_scope_end_f]
                | confix_p(ch_p('{')[parser->object_scope_begin_f],
                           pair >> *(ch_p(',') >> pair),
                           ch_p('}')[parser->object_scope_end_f]);
            pair = str[parser->field_f] >> ch_p(':') >> value;
            
            array = confix_p(ch_p('['), *blank_p, ch_p(']')[parser->empty_array_scope_end_f]) 
                | confix_p(ch_p('[')[parser->array_scope_begin_f],
                           value >> *(ch_p(',') >> value),
                           ch_p(']')[parser->array_scope_end_f]);
            
            value =  strict_real_p[parser->real_f] 
                |  object  
                | (str_p("null")[parser->nil_f]
                   | str_p("true")[parser->true_f]
                   | str_p("false")[parser->false_f]
                   | int_p[parser->int_f]
                   |  str[parser->string_f]) 
                | array; 

            str = confix_p('"', *anychar_p, '"');
            
            
        }
        
      boost::spirit::classic::rule<ScannerT> const& start() const { return object; }        
        
      boost::spirit::classic::rule<ScannerT> object, members, pair, array, elements, str, value, boolean;
    };

public:
    void clean_up() {
        if (!this->pstack.empty()) {
            jost::Object* o =
                jost::extract<jost::Object>(this->pstack.top().value);
            delete o;
        }
    }
    
public:
    parse_stack   pstack;
    
private:
    
    integral_functor<jost::Integer, int,   json_parser>       int_f;
    integral_functor<jost::Real,    float, json_parser>       real_f;
    integral_functor<jost::String,  std::string, json_parser> string_f;

    bool_functor<true, json_parser>  true_f;
    bool_functor<false, json_parser> false_f;
    nil_functor<json_parser>         nil_f;
    
    object_scope_end_functor<json_parser>   object_scope_end_f;
    object_scope_begin_functor<json_parser> object_scope_begin_f;
    array_scope_end_functor<json_parser>    array_scope_end_f;
    array_scope_begin_functor<json_parser>  array_scope_begin_f;


    empty_object_scope_end_functor<json_parser> empty_object_scope_end_f;
    empty_array_scope_end_functor<json_parser> empty_array_scope_end_f;

    field_functor<json_parser> field_f;
    
    jost::Object* parsed_object_;

private:
        // -- Friends -- 
    friend struct object_scope_end_functor<json_parser>;
    
public:
    inline jost::Object* parsed_object() 
        {
            
            return this->parsed_object_;
        }
    
};
} /*namespace jost*/

#endif /*_JOST_JSON_GRAMMAR_H_*/
